package org.example.server.search.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.example.api.search.controller.request.GoodsSearchRequest;
import org.example.api.search.enums.GoodsStatusEnum;
import org.example.frw.api.base.response.PageResponse;
import org.example.server.search.bo.GoodsDocSummaryBo;
import org.example.server.search.doc.GoodsDOC;
import org.example.server.search.mapstruct.GoodsDocConverter;
import org.example.server.search.service.SearchService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class SearchServiceImpl implements SearchService {
    @Resource
    private ElasticsearchClient elasticsearchClient;
    @Resource
    private GoodsDocConverter goodsDocConverter;

    @Override
    @SneakyThrows
    public PageResponse<GoodsDocSummaryBo> searchGoods(GoodsSearchRequest request) {
        SearchRequest searchRequest = SearchRequest.of(
                builder -> builder
                        .index("goods")
                        .query(Query.of(q -> {
                            q.bool(b->{
                                List<Query> mustQuery = new ArrayList<>();
                                // 只展示上架的
                                Query status = Query.of(pp -> pp.term(ppt -> ppt.field("status").value(FieldValue.of(GoodsStatusEnum.ON_SHELVES.getCode()))));
                                // 只展示上架的
                                Query categoryIsDisplay = Query.of(ppn -> ppn.nested(n ->
                                        n.path("category").query(Query.of(p ->
                                                p.term(t->t.field("category.isDisplay").value(FieldValue.of(true)))))
                                ));
                                if(CharSequenceUtil.isNotBlank(request.getCategoryId())){
                                    // 只展示指定分类
                                    Query categoryId = Query.of(ppn -> ppn.nested(n ->
                                            n.path("category").query(Query.of(p ->
                                                    p.term(t->t.field("category.id").value(FieldValue.of(request.getCategoryId())))))
                                    ));
                                    mustQuery.add(categoryId);
                                }
                                mustQuery.add(status);
                                mustQuery.add(categoryIsDisplay);

                                List<Query> shouldQuery = new ArrayList<>();
                                // 关键词模糊查询
                                if(StrUtil.isNotBlank(request.getKeyword())){
                                    Query title = Query.of(sq -> sq.match(sm -> sm.field("title").query(FieldValue.of(request.getKeyword()))));
                                    Query subTitle = Query.of(sq -> sq.match(sm -> sm.field("subTitle").query(FieldValue.of(request.getKeyword()))));
                                    Query categoryName = Query.of(sq -> sq.nested(sn->sn.path("category").query(snq->snq.term(snqt->snqt.field("category.categoryName").value(request.getKeyword())))));
                                    Query categoryPath = Query.of(sq -> sq.nested(sn->sn.path("category").query(snq->snq.term(snqt->snqt.field("category.path").value(request.getKeyword())))));
                                    Query skuDescription = Query.of(sq -> sq.nested(sn->sn.path("skus").query(snq->snq.term(snqt->snqt.field("skus.description").value(request.getKeyword())))));
                                    Query paramsDescription = Query.of(sq -> sq.nested(sn->sn.path("params").query(snq->snq.term(snqt->snqt.field("params.description").value(request.getKeyword())))));
                                    shouldQuery.add(title);
                                    shouldQuery.add(subTitle);
                                    shouldQuery.add(categoryName);
                                    shouldQuery.add(skuDescription);
                                    shouldQuery.add(paramsDescription);
                                    shouldQuery.add(categoryPath);
                                }
                                return b.must(mustQuery).should(shouldQuery);
                            });
                            return q;
                        }))
                        .from(request.getPage().current() - 1)
                        .size(request.getPage().getPageSize())
                        .sort(s->s.field(f->f.field("_score").order(SortOrder.Desc)))
        );
        log.info("searchRequest {}",searchRequest);
        SearchResponse<GoodsDOC> searched = elasticsearchClient.search(searchRequest, GoodsDOC.class);
        PageResponse.PageResponseBuilder<GoodsDocSummaryBo> builder = PageResponse.builder();
        builder.total(0L);
        builder.current(request.getPage().current());
        builder.pageSize(request.getPage().pageSize());

        if (searched.hits().total() != null) {
            long total = searched.hits().total().value();
            builder.total(total);
        }
        List<Hit<GoodsDOC>> hits = searched.hits().hits();
        if(CollUtil.isEmpty(hits)){
            builder.items(new ArrayList<>());
            return builder.build();
        }
        List<GoodsDocSummaryBo> list = hits.stream().map(hit -> goodsDocConverter.toGoodsDocSummaryBo(hit.source())).toList();
        builder.items(list);
        return builder.build();
    }

}
